package org.light.verb;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.light.core.Verb;
import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Dropdown;
import org.light.domain.Field;
import org.light.domain.JavascriptBlock;
import org.light.domain.JavascriptMethod;
import org.light.domain.Method;
import org.light.domain.Signature;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.domain.Type;
import org.light.domain.Var;
import org.light.easyui.EasyUIPositions;
import org.light.generator.NamedStatementGenerator;
import org.light.limitedverb.CountSearchByFieldsRecords;
import org.light.utils.DomainTokenUtil;
import org.light.utils.StringUtil;
import org.light.utils.TableStringUtil;
import org.light.utils.WriteableUtil;

public class SearchByFieldsByPage extends Verb implements EasyUIPositions {
	protected CountSearchByFieldsRecords countSearch = new CountSearchByFieldsRecords();
	
	@Override
	public Method generateDaoImplMethod() throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByLimit");
		method.setNoContainer(true);
		List<Writeable> list = new ArrayList<Writeable>();
		list.add(new Statement(100L,1,"<select id=\""+method.getLowerFirstMethodName()+"\" resultMap=\""+this.domain.getLowerFirstDomainName()+"\">"));
		list.add(new Statement(200L,2,"select "+ DomainTokenUtil.generateTableCommaFields(domain) + " from "+ domain.getDbPrefix() + TableStringUtil.domainNametoTableName(domain)));
		list.add(new Statement(300L,2,"where 1=1 "));
		long serial = 400L;
		Set<Field> fields = this.domain.getFieldsWithoutId();
		for (Field f:fields){
			if (f.getFieldType().equalsIgnoreCase("string")){
				list.add(new Statement(serial,2,"<if test=\""+this.domain.getLowerFirstDomainName()+"."+f.getLowerFirstFieldName()+"!=null and "+this.domain.getLowerFirstDomainName()+"."+f.getLowerFirstFieldName()+"!='' \">"));
				list.add(new Statement(serial+100,3,"and "+DomainTokenUtil.changeDomainFieldtoTableColum(f.getLowerFirstFieldName())+" LIKE CONCAT(CONCAT('%', #{"+this.domain.getLowerFirstDomainName()+"."+f.getLowerFirstFieldName()+"}),'%')"));
			}else{
				list.add(new Statement(serial,2,"<if test=\""+this.domain.getLowerFirstDomainName()+"."+f.getLowerFirstFieldName()+"!=null\">"));
				list.add(new Statement(serial+100,3,"and "+DomainTokenUtil.changeDomainFieldtoTableColum(f.getLowerFirstFieldName())+" = #{"+this.domain.getLowerFirstDomainName()+"."+f.getLowerFirstFieldName()+"}"));
			}
			list.add(new Statement(serial+200,2,"</if>"));
			serial += 300L;
		}
		list.add(new Statement(serial,2,"limit #{limit} offset #{start}"));
		list.add(new Statement(serial+100L,1,"</select>"));
		method.setMethodStatementList(WriteableUtil.merge(list));
		return method;
	}

	@Override
	public String generateDaoImplMethodString() throws Exception{
		Method m = this.generateDaoImplMethod();
		String s = m.generateMethodString();
		return s;
	}

	@Override
	public Method generateDaoMethodDefinition()  throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByLimit");
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport("org.apache.ibatis.annotations.Param");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType(),this.domain.getPackageToken(),"Param(value=\""+this.domain.getLowerFirstDomainName()+"\")"));
		method.addSignature(new Signature(2,"start",new Type("Integer"),"","Param(value=\"start\")"));
		method.addSignature(new Signature(3,"limit",new Type("Integer"),"","Param(value=\"limit\")"));
		method.setThrowException(true);
		
		return method;
	}

	@Override
	public String generateDaoMethodDefinitionString()  throws Exception{
		return generateDaoMethodDefinition().generateMethodDefinition();
	}

	@Override
	public String generateDaoImplMethodStringWithSerial()  throws Exception{
		Method m = this.generateDaoImplMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}

	@Override
	public Method generateServiceMethodDefinition()  throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType()));
		method.addSignature(new Signature(2,"pagesize",new Type("Integer")));
		method.addSignature(new Signature(3,"pagenum",new Type("Integer")));
		method.setThrowException(true);
		
		return method;
	}

	@Override
	public String generateServiceMethodDefinitionString()  throws Exception{
		return generateServiceMethodDefinition().generateMethodDefinition();
	}

	@Override
	public Method generateServiceImplMethod()  throws Exception{
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		method.setReturnType(new Type("List",this.domain, this.domain.getPackageToken()));
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType()));
		method.addSignature(new Signature(2,"pagesize",new Type("Integer")));
		method.addSignature(new Signature(3,"pagenum",new Type("Integer")));
		method.setThrowException(true);
		
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addAdditionalImport(this.domain.getPackageToken()+".dao."+this.domain.getStandardName()+"Dao");
		method.addAdditionalImport(this.domain.getPackageToken()+".service."+this.domain.getStandardName()+"Service");

		method.addMetaData("Override");
		
		List<Writeable> list = new ArrayList<Writeable>();
		list.add(new Statement(1000L,2,"Integer start = (pagenum-1)*pagesize;"));
		list.add(new Statement(2000L,2,"Integer limit = pagesize;"));
		list.add(new Statement(3000L,2,"return dao.search"+this.domain.getCapFirstPlural()+"ByFieldsByLimit("+this.domain.getLowerFirstDomainName()+",start,limit);"));	
		method.setMethodStatementList(WriteableUtil.merge(list));

		return method;
	}

	@Override
	public String generateServiceImplMethodString()  throws Exception{
		return generateServiceImplMethod().generateMethodString();
	}

	@Override
	public String generateServiceImplMethodStringWithSerial()  throws Exception{
		Method m = this.generateServiceImplMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}
	
	public SearchByFieldsByPage(){
		super();
		this.setLabel("按字段分页搜索");
	}
	
	public SearchByFieldsByPage(Domain domain){
		super();
		this.domain = domain;
		this.setVerbName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		this.setLabel("按字段分页搜索");
	}

	@Override
	public Method generateControllerMethod()  throws Exception{
		this.countSearch.setDomain(this.domain);
		
		Method method = new Method();
		method.setStandardName("search"+StringUtil.capFirst(this.domain.getPlural())+"ByFieldsByPage");
		method.setReturnType(new Type("Map<String,Object>"));
		method.setThrowException(true);
		method.addAdditionalImport("java.util.List");
		method.addAdditionalImport(this.domain.getPackageToken()+".utils.BooleanUtil");
		method.addAdditionalImport(this.domain.getPackageToken()+".domain."+this.domain.getStandardName());
		method.addAdditionalImport(this.domain.getPackageToken()+".service."+this.domain.getStandardName()+"Service");
		method.addSignature(new Signature(1,"pagenum",new Type("Integer"), "","RequestParam(value = \"page\", required = false)"));
		method.addSignature(new Signature(2,"pagesize",new Type("Integer"), "","RequestParam(value = \"rows\", required = false)"));
		method.addSignature(new Signature(3,"lastFlag",new Type("String"), "","RequestParam(value = \"last\", required = false)"));
		int sigPos = 4;
		for (Field f:this.domain.getFieldsWithoutId()){
			if (f.getFieldType().equalsIgnoreCase("Boolean")){
				method.addSignature(new Signature(sigPos,f.getLowerFirstFieldName(),new Type("String"), "","RequestParam(value = \""+f.getLowerFirstFieldName()+"\", required = false)"));
			}else {
				method.addSignature(new Signature(sigPos,f.getLowerFirstFieldName(),f.getClassType(), "","RequestParam(value = \""+f.getLowerFirstFieldName()+"\", required = false)"));	
			}
			sigPos ++;
		}
		method.addMetaData("RequestMapping(value = \"/"+StringUtil.lowerFirst(method.getStandardName())+"\", method = RequestMethod.POST)");
		
		List<Writeable> wlist = new ArrayList<Writeable>();
		Var service = new Var("service", new Type(this.domain.getStandardName()+"Service",this.domain.getPackageToken()));
		Var vlist = new Var(this.domain.getLowerFirstDomainName()+"List", new Type("List",this.domain,this.domain.getPackageToken()));
		Method serviceMethod = this.generateServiceMethodDefinition();
		Var resultMap = new Var("result", new Type("TreeMap<String,Object>","java.util"));
		wlist.add(new Statement(1000L,2,this.domain.getCapFirstDomainName()+" "+this.domain.getLowerFirstDomainName()+" = new "+this.domain.getCapFirstDomainName()+"();"));
		
		long serial = 2000L;
		for (Field f: this.domain.getFieldsWithoutId()){
			if (f.getFieldType().equalsIgnoreCase("Boolean")){
				wlist.add(new Statement(serial,2,"Boolean "+f.getLowerFirstFieldName()+"Bool = BooleanUtil.parseBoolean("+f.getLowerFirstFieldName()+");"));
				wlist.add(new Statement(serial+500L,2,"if ("+f.getLowerFirstFieldName()+"Bool != null) "+this.domain.getLowerFirstDomainName()+"."+f.getSetterCallName()+"("+f.getLowerFirstFieldName()+"Bool);"));
			}else {
				wlist.add(new Statement(serial,2,"if ("+f.getLowerFirstFieldName()+" != null) "+this.domain.getLowerFirstDomainName()+"."+f.getSetterCallName()+"("+f.getLowerFirstFieldName()+");"));
			}
			serial +=  1000L;
		}
		
		wlist.add(new Statement(serial,2,"if (pagesize==null || pagesize <= 0) pagesize = 10;"));
		wlist.add(new Statement(serial+1000L,2,"Integer recordCount = service.countSearch"+this.domain.getCapFirstPlural()+"ByFieldsRecords("+this.domain.getLowerFirstDomainName()+");"));
		wlist.add(new Statement(serial+2000L,2,"Integer pageCount = (int)Math.ceil((double)recordCount/pagesize);"));
		wlist.add(new Statement(serial+2500L,2,"if (pageCount <= 1) pageCount = 1;"));
		wlist.add(new Statement(serial+3000L,2,"if (pagenum==null || pagenum <= 1) pagenum = 1;"));
		wlist.add(new Statement(serial+4000L,2,"if (pagenum >= pageCount) pagenum = pageCount;"));
		wlist.add(new Statement(serial+5000L,2,"Boolean lastFlagBool = BooleanUtil.parseBoolean(lastFlag);"));
		wlist.add(new Statement(serial+6000L,2,"if (lastFlagBool == null) lastFlagBool = false;"));
		wlist.add(new Statement(serial+7000L,2,"if (lastFlagBool) pagenum = pageCount;"));		
		
		wlist.add(NamedStatementGenerator.getJsonResultMap(serial+8000L, 2, resultMap));
		wlist.add(new Statement(serial + 9000L,2,vlist.getVarType() + " " + vlist.getVarName() +" = " + service.getVarName()+"."+serviceMethod.generateStandardCallString()+";"));
		wlist.add(new Statement(serial + 10000L,2,resultMap.getVarName() +".put(\"success\",true);"));
		wlist.add(new Statement(serial + 11000L,2,resultMap.getVarName() +".put(\"rows\","+vlist.getVarName()+");"));
		wlist.add(new Statement(serial + 12000L,2,resultMap.getVarName() +".put(\"total\",recordCount);"));
		wlist.add(new Statement(serial + 13000L,2,resultMap.getVarName() +".put(\"page\",pagenum);"));
		wlist.add(new Statement(serial + 14000L, 2, "return " + resultMap.getVarName()+";"));	
		method.setMethodStatementList(WriteableUtil.merge(wlist));
		
		return method;
	}

	@Override
	public String generateControllerMethodString()  throws Exception{
		Method m = this.generateControllerMethod();
		return m.generateMethodString();
	}

	@Override
	public String generateControllerMethodStringWithSerial()  throws Exception{
		Method m = this.generateControllerMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}

	@Override
	public JavascriptBlock generateEasyUIJSButtonBlock() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String generateEasyUIJSButtonBlockString() throws Exception {
		return generateEasyUIJSButtonBlock().generateBlockContentString();
	}

	@Override
	public String generateEasyUIJSButtonBlockStringWithSerial() throws Exception {
		return generateEasyUIJSButtonBlock().generateBlockContentStringWithSerial();
	}

	@Override
	public JavascriptMethod generateEasyUIJSActionMethod() throws Exception {
		Domain domain = this.domain;
		JavascriptMethod method = new JavascriptMethod();
		method.setSerial(200);
		method.setStandardName("search"+domain.getPlural()+"ByFieldsByPage");
				
		StatementList sl = new StatementList();
		sl.add(new Statement(1000,1, "params = {"));
		long serial = 2000;
		for (Field f: domain.getFieldsWithoutId()){
			if (f instanceof Dropdown)
				sl.add(new Statement(serial,2, f.getLowerFirstFieldName()+":$(\"#ffsearch\").find(\"#"+f.getLowerFirstFieldName()+"\").combobox(\"getValue\"),"));
			else if (!f.getFieldType().equalsIgnoreCase("boolean"))
				sl.add(new Statement(serial,2, f.getLowerFirstFieldName()+":$(\"#ffsearch\").find(\"#"+f.getLowerFirstFieldName()+"\").val(),"));
			else 
				sl.add(new Statement(serial,2, f.getLowerFirstFieldName()+":parseBoolean($(\"#ffsearch\").find(\"#"+f.getLowerFirstFieldName()+"\").val()),"));
			serial+=1000;
		}	
		sl.add(new Statement(serial,1, "};"));
		sl.add(new Statement(serial+1000,1, "$(\"#dg\").datagrid({queryParams:params});"));
		
		method.setMethodStatementList(sl);
		return method;	
	}

	@Override
	public String generateEasyUIJSActionString() throws Exception {
		return generateEasyUIJSActionMethod().generateMethodString();
	}

	@Override
	public String generateEasyUIJSActionStringWithSerial() throws Exception {
		return generateEasyUIJSActionMethod().generateMethodString();
	}

}
